home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - portable sources / libraries / dylan / coll.dylan < prev    next >
Encoding:
Text File  |  1995-03-15  |  32.9 KB  |  1,030 lines  |  [TEXT/ttxt]

  1. module: Dylan
  2. author: William Lott (wlott@cs.cmu.edu)
  3. rcs-header: $Header: coll.dylan,v 1.24 94/12/14 20:18:44 rgs Exp $
  4.  
  5. //======================================================================
  6. //
  7. // Copyright (c) 1994  Carnegie Mellon University
  8. // All rights reserved.
  9. // 
  10. // Use and copying of this software and preparation of derivative
  11. // works based on this software are permitted, including commercial
  12. // use, provided that the following conditions are observed:
  13. // 
  14. // 1. This copyright notice must be retained in full on any copies
  15. //    and on appropriate parts of any derivative works.
  16. // 2. Documentation (paper or online) accompanying any system that
  17. //    incorporates this software, or any part of it, must acknowledge
  18. //    the contribution of the Gwydion Project at Carnegie Mellon
  19. //    University.
  20. // 
  21. // This software is made available "as is".  Neither the authors nor
  22. // Carnegie Mellon University make any warranty about the software,
  23. // its performance, or its conformity to any specification.
  24. // 
  25. // Bug reports, questions, comments, and suggestions should be sent by
  26. // E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  27. //
  28. //======================================================================
  29. //
  30. // This file contains the collection support code that isn't built in.
  31. //
  32.  
  33. define constant no_default :: <pair> = pair(#f, #f);
  34.  
  35.  
  36. // Collection routines
  37.  
  38. // We inherit the iteration protocol from the subclasses, which must define
  39. // it. 
  40. // define generic forward-iteration-protocol(collection);
  41.  
  42. // Element and element-setter will be implemented for arrays and vectors, but
  43. // we must define a default method for all collections.
  44. //
  45. define method element(coll :: <collection>, key :: <object>,
  46.               #key default = no_default) => <object>;
  47.   let (init-state, limit, next-state, done?,
  48.        current-key, current-element) = forward-iteration-protocol(coll);
  49.   let test = key-test(coll);
  50.   block (return)
  51.     for (state = init-state then next-state(coll, state),
  52.      until done?(coll, state, limit))
  53.       if (test(current-key(coll, state), key))
  54.     return(current-element(coll, state));
  55.       end if;
  56.     finally
  57.       if (default == no_default)
  58.     error("No such element in %=: %=", coll, key);
  59.       else 
  60.     default;
  61.       end if;
  62.     end for;
  63.   end block;
  64. end method element;
  65.  
  66.  
  67. define method element-setter (new-value :: <object>,
  68.                   collection :: <mutable-collection>,
  69.                   key :: <object>) => new-value :: <object>;
  70.   let (init-state, limit, next-state, done?,
  71.        current-key, current-element,
  72.        current-element-setter) = forward-iteration-protocol(collection);
  73.   let test = key-test(collection);
  74.   block (return)
  75.     for (state = init-state then next-state(collection, state),
  76.      until done?(collection, state, limit))
  77.       if (test(current-key(collection, state), key))
  78.     current-element(collection, state) := new-value;
  79.     return();
  80.       end if;
  81.     end for;
  82.     error("No such element in %=: %=", collection, key);
  83.   end block;
  84. end method element-setter;
  85.  
  86.  
  87. define method shallow-copy(collection :: <collection>) => <collection>;
  88.   map(identity, collection);
  89. end method shallow-copy;
  90.  
  91.  
  92. define method as(cls :: limited(<class>, subclass-of: <collection>),
  93.          coll :: <collection>, #next next-method) => <object>;
  94.   case
  95.     instance?(coll, cls) =>
  96.       coll;
  97.     otherwise =>
  98.       map-as(cls, identity, coll);
  99.   end case;
  100. end method as;
  101.  
  102.  
  103. // Note: This function depends upon a definition of \= for sequences, which
  104. // will be supplied later in this file.
  105. //
  106. define method \=(a :: <collection>, b :: <collection>) => <object>;
  107.   let a-test = key-test(a);
  108.   let b-test = key-test(b);
  109.   
  110.   a-test == b-test
  111.     & key-sequence(a) = key-sequence(b) 
  112.     & every?(a-test, a, b);
  113. end method \=;
  114.  
  115.  
  116. define method size(collection :: <collection>) => <fixed-integer>;
  117.   for (count from 0, elem in collection)
  118.   finally
  119.     count;
  120.   end for;
  121. end method size;
  122.  
  123.  
  124. define method class-for-copy(collection :: <mutable-collection>) => <class>;
  125.   object-class(collection);
  126. end method class-for-copy;
  127.  
  128.  
  129. define method empty?(collection :: <collection>) => <object>;
  130.   let (init, limit, next, done?) = forward-iteration-protocol(collection);
  131.   done?(collection, init, limit);
  132. end method empty?;
  133.  
  134.  
  135. // Note: the map methods for arbitrary collections depend upon the iteration
  136. // protocol being defined for "rest args" (i.e. vectors).
  137. //
  138. define method do(proc :: <function>, collection :: <collection>,
  139.          #rest more-collections)
  140.   let test1 = key-test(collection);
  141.   if (~ every?( method (c) test1 == key-test(c); end, more-collections ))
  142.     error("Can't do over collections with different key tests");
  143.   elseif (empty?(more-collections))
  144.     for (elem in collection) 
  145.       proc(elem);
  146.     end for;
  147.   else
  148.     let keys = reduce(rcurry(intersection, test: test1),
  149.               key-sequence(collection),
  150.               map(key-sequence, more-collections));
  151.     for (key in keys)
  152.       apply(proc, collection[key],
  153.         map(rcurry(element, key), more-collections));
  154.     end for;
  155.   end if;
  156. end method do;
  157.  
  158.  
  159. define method map(proc :: <function>, collection :: <collection>,
  160.           #rest more-collections) => <collection>;
  161.   apply(map-as, class-for-copy(collection), proc, collection,
  162.     more-collections);
  163. end method map;
  164.  
  165.  
  166. // map-as must be given collections with the same key tests, but the
  167. // output collection apparently doesn't have to have the same key test
  168. // as its inputs.
  169. //
  170. define method map-as(cls :: <class>, proc :: <function>,
  171.              coll :: <collection>, #rest more-collections)
  172.     => <collection>;
  173.   let test = key-test(coll);
  174.   case
  175.     ~every?(method (c) key-test(c) == test end, more-collections) =>
  176.       error("Can't map over collections with different key tests");
  177.     size(coll) == #f
  178.       & every?(method (s) size(s) == #f end, more-collections) =>
  179.       error("Map-as not applicable to unbounded collections");
  180.     empty?(more-collections) =>
  181.       let result = make(cls, size: size(coll));
  182.       let (init, limit, next, done?, curkey, curelt)
  183.         = forward-iteration-protocol(coll);
  184.       for (state = init then next(coll, state),
  185.        until done?(coll, state, limit))
  186.     result[curkey(coll, state)] := proc(curelt(coll, state));
  187.       end for;
  188.       result;
  189.     otherwise => 
  190.       let keys = reduce(rcurry(intersection, test: test),
  191.             key-sequence(coll),
  192.             map(key-sequence, more-collections));
  193.       let result = make(cls, size: size (keys));
  194.       for (key in keys)
  195.     result[key] := apply(proc, element (coll, key),
  196.                  map(rcurry (element, key),
  197.                  more-collections));
  198.       end for;
  199.       result;
  200.   end case;
  201. end method map-as;
  202.  
  203.  
  204. // map-into must be given collections with the same key tests, and the
  205. // destination must have the same key test as the sources.
  206. //
  207. define method map-into(destination :: <mutable-collection>, proc :: <function>,
  208.                coll :: <collection>, #rest more-collections)
  209.     => <collection>;
  210.   let test1 = key-test(coll);
  211.   if (~ every?(method (c) test1 == key-test(c); end, more-collections ))
  212.     error("Can't map over collections with different key tests");
  213.   elseif (~ (test1 == key-test(destination)))
  214.     error("Can't map into a collection with a different key test than its sources.");
  215.   elseif (empty?(more-collections))
  216.     let keys = intersection(key-sequence(coll), key-sequence(destination),
  217.                 test: test1);
  218.     for (key in keys)
  219.       destination[key] := proc(coll[key]);
  220.     end for;
  221.     destination;
  222.   else
  223.     let keys = intersection(reduce(rcurry(intersection, test: test1),
  224.                    key-sequence(coll),
  225.                    map(key-sequence, more-collections)),
  226.                 key-sequence(destination), test: test1);
  227.     for (key in keys)
  228.       destination[key] := apply(proc, coll[key],
  229.                 map(rcurry(element, key), more-collections));
  230.     end for;
  231.     destination;
  232.   end if;
  233. end method map-into;
  234.  
  235.  
  236. define method any?(proc :: <function>, collection :: <collection>,
  237.            #rest more-collections) => <object>;
  238.   let test1 = key-test(collection);
  239.   if (~ every?( method (c) test1 == key-test(c); end, more-collections))
  240.     error("Can't do collection alignment over collections with different key tests");
  241.   end if;
  242.  
  243.   block (return)
  244.     if (empty?(more-collections))
  245.       for (elem in collection)
  246.     let result = proc(elem);
  247.     if (result) return(result) end if;
  248.       end for;
  249.     else 
  250.       let keys = reduce(rcurry(intersection, test: test1),
  251.             key-sequence(collection),
  252.             map(key-sequence, more-collections));
  253.       for (key in keys)
  254.     let result = apply(proc, collection[key],
  255.                map(rcurry(element, key), more-collections));
  256.     if (result) return(result) end if;
  257.       end for;
  258.     end if;
  259.     #f;
  260.   end block;
  261. end method any?;
  262.  
  263.  
  264. define method every?(proc :: <function>, collection :: <collection>,
  265.            #rest more-collections) => <object>;
  266.   let test1 = key-test(collection);
  267.   if (~ every?( method (c) test1 == key-test(c); end, more-collections ))
  268.     error("Can't do collection alignment over collections with different key tests");
  269.   end if;
  270.  
  271.   block (return)
  272.     if (empty?(more-collections))
  273.       for (elem in collection)
  274.     unless (proc(elem)) return(#f) end unless;
  275.       end for;
  276.     else
  277.       let keys = reduce(rcurry(intersection, test: test1),
  278.             key-sequence(collection),
  279.             map(key-sequence, more-collections));
  280.       for (key in keys)
  281.     let result = apply(proc, collection[key],
  282.                map(rcurry(element, key), more-collections));
  283.     unless (result) return(#f) end unless;
  284.       end for;
  285.     end if;
  286.     #t;
  287.   end block;
  288. end method every?;
  289.  
  290.  
  291. define method reduce(proc :: <function>, init-val, collection :: <collection>)
  292.   for (value = init-val then proc(value, elem),
  293.        elem in collection)
  294.   finally value;
  295.   end for;
  296. end method reduce;
  297.  
  298.  
  299. define method reduce1(proc :: <function>, collection :: <collection>)
  300.   let (init-state, limit, next-state, done?,
  301.        current-key, current-element) = forward-iteration-protocol(collection);
  302.   if (done?(collection, init-state, limit)) // empty collection
  303.     error("Reduce1 not defined for empty collections.");
  304.   else 
  305.     for (// The computation of "value" must precede the computation of "state",
  306.      // since "next-state" may invalidate the current state.
  307.      value = current-element(collection, init-state)
  308.        then proc(value, current-element(collection, state)),
  309.      state = next-state(collection, init-state)
  310.        then next-state(collection, state),
  311.      until done?(collection, state, limit))
  312.     finally value;
  313.     end for;
  314.   end if;
  315. end method reduce1;
  316.  
  317.  
  318. define method member?(value :: <object>, collection :: <collection>,
  319.               #key test = \==) => <object>;
  320.   block (return)
  321.     for (element in collection)
  322.       if (test(value, element)) return(#t) end if;
  323.     end for;
  324.   end block;
  325. end method member?;
  326.  
  327.  
  328. define method replace-elements!(collection :: <mutable-collection>,
  329.                 predicate :: <function>,
  330.                 new-value-fn :: <function>,
  331.                 #key count: count) => <mutable-collection>;
  332.   let (init-state, limit, next-state, done?,
  333.        current-key, current-element,
  334.        current-element-setter) = forward-iteration-protocol(collection);
  335.   for (state = init-state then next-state(collection, state),
  336.        until done?(collection, state, limit) | count == 0)
  337.     let this-element = current-element(collection, state);
  338.     if (predicate(this-element))
  339.       current-element(collection, state) := new-value-fn(this-element);
  340.       if (count) count := count - 1 end if;
  341.     end if;
  342.   end for;
  343.   collection;
  344. end method replace-elements!;
  345.  
  346.  
  347. define method fill!(collection :: <mutable-collection>, value :: <object>,
  348.             #key start: first, end: last) => <mutable-collection>;
  349.   // ignore keywords, since they aren't meaningful for arbitrary collections.
  350.   let (init-state, limit, next-state, done?,
  351.        current-key, current-element,
  352.        current-element-setter) = forward-iteration-protocol(collection);
  353.   for (state = init-state then next-state(collection, state),
  354.        until done?(collection, state, limit))
  355.     current-element(collection, state) := value;
  356.   end for;
  357.   collection;
  358. end method fill!;
  359.  
  360.  
  361. define method find-key(collection :: <collection>, proc :: <function>,
  362.                #key skip, failure = #f)
  363.   let (init-state, limit, next-state, done?,
  364.        current-key, current-element) = forward-iteration-protocol(collection);
  365.   block (return)
  366.     for (state = init-state then next-state(collection, state),
  367.      until done?(collection, state, limit))
  368.       if (proc(current-element(collection, state)))
  369.     if (skip & skip > 0)
  370.       skip := skip - 1;
  371.     else
  372.       return(current-key(collection, state));
  373.     end if;
  374.       end if;
  375.     finally failure
  376.     end for;
  377.   end block;
  378. end method find-key;
  379.  
  380.  
  381. define method key-sequence(collection :: <collection>) => <collection>;
  382.   let (init-state, limit, next-state, done?,
  383.        current-key, current-element) = forward-iteration-protocol(collection);
  384.   let result = make(<vector>, size: size(collection));
  385.   for (index from 0,
  386.        state = init-state then next-state(collection, state),
  387.        until done?(collection, state, limit))
  388.     result[index] := current-key(collection, state);
  389.   end for;
  390.   result;
  391. end method key-sequence;
  392.  
  393.  
  394. // Sequence routines.
  395.  
  396. define method element(sequence :: <sequence>, key :: <integer>,
  397.               #key default = no_default) => <object>;
  398.   block (return)
  399.     for (this-key from 0, elem in sequence)
  400.       if (this-key == key) return(elem) end if;
  401.     finally
  402.       if (default == no_default)
  403.     error("No such element in %=: %=", sequence, key);
  404.       else 
  405.     default;
  406.       end if;
  407.     end for;
  408.   end block;
  409. end method element;
  410.  
  411.  
  412. define method element-setter (new-value, sequence :: <mutable-sequence>,
  413.                   key :: <integer>)
  414.   let (init-state, limit, next-state, done?,
  415.        current-key, current-element,
  416.        current-element-setter) = forward-iteration-protocol(sequence);
  417.   block (return)
  418.     for (this-key from 0,
  419.      state = init-state then next-state(sequence, state),
  420.      until done?(sequence, state, limit))
  421.       if (this-key == key)
  422.     current-element(sequence, state) := new-value;
  423.     return();
  424.       end if;
  425.     end for;
  426.     error("No such element in %=: %=", sequence, key);
  427.   end block;
  428. end method element-setter;
  429.  
  430.  
  431. define method \=(a :: <sequence>, b :: <sequence>) => <object>;
  432.   let (a-init, a-limit, a-next, a-done?, a-key, a-elem)
  433.     = forward-iteration-protocol(a);
  434.   let (b-init, b-limit, b-next, b-done?, b-key, b-elem)
  435.     = forward-iteration-protocol(b);
  436.   block (return)
  437.     for (a-state = a-init then a-next(a, a-state),
  438.      b-state = b-init then b-next(b, b-state),
  439.      until a-done?(a, a-state, a-limit) | b-done?(b, b-state, b-limit))
  440.       if (a-elem(a, a-state) ~= b-elem(b, b-state))
  441.     return(#f);
  442.       end if;
  443.     finally
  444.       if (~a-done?(a, a-state, a-limit) | ~b-done?(b, b-state, b-limit))
  445.     return(#f);
  446.       end if;
  447.     end for;
  448.     #t;
  449.   end block;
  450. end method \=;
  451.  
  452.  
  453. define method key-test (sequence :: <sequence>) => test :: <function>;
  454.   \==;            // Return the function == (id?)
  455. end method key-test;
  456.  
  457.  
  458. define method key-sequence(sequence :: <sequence>) => <range>;
  459.   let s = size (sequence);
  460.   if (s)
  461.     range (from: 0, below: s);
  462.   else
  463.     range (from: 0);
  464.   end if;
  465. end method key-sequence;
  466.  
  467.  
  468. define constant aux-map-as =
  469.   method (cls :: <class>, proc :: <function>, #rest seqs)
  470.     let finite-lengths = choose (identity, map (size, seqs));
  471.     let length = apply(min, finite-lengths);
  472.     let result = make(cls, size: length);
  473.     let (init, limit, next, done?, key, elem, elem-setter)
  474.       = forward-iteration-protocol(result);
  475.     let seq-count = size(seqs);
  476.     let states = make(<vector>, size: seq-count);
  477.     let vals = make(<vector>, size: seq-count);
  478.     let nexts = make(<vector>, size: seq-count);
  479.     let elems = make(<vector>, size: seq-count);
  480.  
  481.     for (pos from 0, seq in seqs)
  482.       let (init, limit, next, done?, key, elem)
  483.     = forward-iteration-protocol(seq);
  484.       states[pos] := init;
  485.       nexts[pos] := next;
  486.       elems[pos] := elem;
  487.     end for;
  488.  
  489.     for (state = init then next(result, state),
  490.      until done?(result, state, limit))
  491.       for (i from 0 below seq-count)
  492.     let (this-seq, this-state) = values(seqs[i], states[i]);
  493.     vals[i] := elems[i](this-seq, this-state);
  494.     states[i] := nexts[i](this-seq, this-state);
  495.       end for;
  496.       elem(result, state) := apply(proc, vals);
  497.     end for;
  498.  
  499.     result;
  500.   end method;
  501.  
  502.  
  503. define method map-as(cls :: <class>, proc :: <function>,
  504.              sequence :: <sequence>,
  505.              #next next-method, #rest more-sequences)
  506.   case
  507.     size (sequence) == #f
  508.       & every? (method (s) size (s) == #f end, more-sequences) =>
  509.       error ("MAP-AS not applicable to unbounded sequences");
  510.     empty?(more-sequences) =>
  511.       let result = make(cls, size: size(sequence));
  512.       let (res-init, res-limit, res-next, res-done?, res-key, res-elem,
  513.        res-elem-setter) = forward-iteration-protocol(result);
  514.       for (element in sequence,
  515.        res-state = res-init then res-next(result, res-state))
  516.     res-elem(result, res-state) := proc(element);
  517.       end for;
  518.       result;
  519.     every?(rcurry(instance?, <sequence>), more-sequences) =>
  520.       apply(aux-map-as, cls, proc, sequence, more-sequences);
  521.     otherwise =>
  522.       next-method();
  523.   end case;
  524. end method map-as;
  525.  
  526.  
  527. define method map-into(destination :: <mutable-sequence>, proc :: <function>,
  528.                sequence :: <sequence>,
  529.                #next next-method, #rest more-sequences)
  530.   if (empty?(more-sequences))
  531.     let (res-init, res-limit, res-next, res-done?, res-key, res-elem,
  532.      res-elem-setter) = forward-iteration-protocol(destination);
  533.     for (element in sequence,
  534.      res-state = res-init then res-next(destination, res-state),
  535.      until res-done?(destination, res-state, res-limit))
  536.       res-elem(destination, res-state) := proc(element);
  537.     end for;
  538.     destination;
  539.   else
  540.     next-method();
  541.   end if;
  542. end method map-into;
  543.  
  544.  
  545. define method fill!(sequence :: <mutable-sequence>, value :: <object>,
  546.             #next next-method,
  547.             #key start: first = 0, end: last) => <mutable-sequence>;
  548.   // The "collection" method will likely be faster if there are no keywrds.
  549.   if (first = 0 & ~last) next-method() end if;
  550.     
  551.   let (init-state, limit, next-state, done?,
  552.        current-key, current-element,
  553.        current-element-setter) = forward-iteration-protocol(sequence);
  554.   for (state = init-state then next-state(sequence, state),
  555.        index from 0 below first,
  556.        until done?(sequence, state, limit))
  557.   finally
  558.     if (last)
  559.       for (state = state then next-state(sequence, state),
  560.        index from index below last,
  561.        until done?(sequence, state, limit))
  562.     current-element(sequence, state) := value;
  563.       end for;
  564.     else
  565.       for (state = state then next-state(sequence, state),
  566.        until done?(sequence, state, limit))
  567.     current-element(sequence, state) := value;
  568.       end for;
  569.     end if;
  570.   end for;
  571.   sequence;
  572. end method fill!;
  573.  
  574.  
  575. define method find-key(sequence :: <sequence>, proc :: <function>,
  576.                #key skip, failure = #f)
  577.   let (init-state, limit, next-state, done?,
  578.        current-key, current-element) = forward-iteration-protocol(sequence);
  579.   block (return)
  580.     for (elem in sequence,
  581.      key from 0)
  582.       if (proc(elem))
  583.     if (skip & skip > 0)
  584.       skip := skip - 1;
  585.     else
  586.       return(key);
  587.     end if;
  588.       end if;
  589.     finally failure
  590.     end for;
  591.   end block;
  592. end method find-key;
  593.  
  594.  
  595. define method add(sequence :: <sequence>, new-element) => <sequence>;
  596.   let old-size = size(sequence);
  597.   let result = make(class-for-copy(sequence), size: old-size + 1);
  598.   map-into(result, identity, sequence);
  599.   result[old-size] := new-element;
  600.   result;
  601. end method add;
  602.  
  603.  
  604. define method add!(sequence :: <sequence>, new-element) => <sequence>;
  605.   add(sequence, new-element);
  606. end method add!;
  607.  
  608.  
  609. define method add-new(sequence :: <sequence>, new-element,
  610.               #key test = \==) => <sequence>;
  611.   if (any?(rcurry(test, new-element), sequence))
  612.     sequence;
  613.   else
  614.     add(sequence, new-element);
  615.   end if;
  616. end method add-new;
  617.  
  618.  
  619. define method add-new!(sequence :: <sequence>, new-element,
  620.               #key test = \==) => <sequence>;
  621.   if (any?(rcurry(test, new-element), sequence))
  622.     sequence;
  623.   else
  624.     add!(sequence, new-element);
  625.   end if;
  626. end method add-new!;
  627.  
  628.  
  629. define method remove(sequence :: <sequence>, value,
  630.              #key test = \==, count) => <sequence>;
  631.   for (result = #() then if (count = 0)
  632.                pair(elem, result);
  633.              elseif (~test(elem, value))
  634.                if (count) count := count - 1 end if;
  635.                pair(elem, result);
  636.              else result
  637.              end if,
  638.        elem in sequence)
  639.   finally
  640.     as(class-for-copy(sequence), reverse!(result));
  641.   end for;
  642. end remove;
  643.  
  644.  
  645. define method remove!(sequence :: <sequence>, value,
  646.               #key test = \==, count: count) => <sequence>;
  647.   remove(sequence, value, test: test, count: count);
  648. end method remove!;
  649.  
  650.  
  651. define generic size-setter(length, collection);
  652.  
  653.  
  654. define method shrink!(sequence :: <sequence>, length) => <sequence>;
  655.   if (applicable-method?(size-setter, length, sequence))
  656.     copy-sequence(sequence, end: length);
  657.   else
  658.     size(sequence) := length;
  659.   end if;
  660. end method;
  661.  
  662.  
  663. define method remove! (sequence :: <mutable-sequence>, value,
  664.                #key test = \==, count: count) => <sequence>;
  665.   let (init-state, limit, next-state, done?, current-key,
  666.        current-element, current-element-setter,
  667.        copy-state) = forward-iteration-protocol(sequence);
  668.   local method replace (dest-state, src-state,
  669.             replaced :: <fixed-integer>, length :: <fixed-integer>)
  670.       case
  671.         done?(sequence, src-state, limit) =>
  672.           shrink!(sequence, length);
  673.         replaced = count =>
  674.           for (dest-state = dest-state
  675.              then next-state(sequence, dest-state),
  676.            src-state = src-state then next-state(sequence, src-state),
  677.            length from length,
  678.            until done?(sequence, src-state, limit))
  679.         current-element(sequence, dest-state)
  680.           := current-element(sequence, src-state);
  681.           finally
  682.         shrink!(sequence, length);
  683.           end for;
  684.         test(current-element(sequence, src-state), value) =>
  685.           replace(dest-state, next-state(sequence, src-state),
  686.               replaced + 1, length);
  687.         otherwise =>
  688.           current-element(sequence, dest-state)
  689.             := current-element(sequence, src-state);
  690.           replace(next-state(sequence, dest-state),
  691.               next-state(sequence, src-state), replaced, length + 1);
  692.       end case;
  693.     end method replace;
  694.   if (count = 0)
  695.     sequence;
  696.   else 
  697.     block (return)
  698.       for (state = init-state then next-state(sequence, state),
  699.        length from 0,
  700.        until done?(sequence, state, limit))
  701.     if (test(current-element(sequence, state), value))
  702.       return(replace(copy-state(sequence, state),
  703.              next-state(sequence, state), 1, length));
  704.     end if;
  705.       finally
  706.     sequence;
  707.       end for;
  708.     end block;
  709.   end if;
  710. end method remove!;
  711.  
  712.  
  713. define method choose(predicate :: <function>,
  714.              sequence :: <sequence>) => <sequence>;
  715.   for (result = #() then if (predicate(elem)) pair(elem, result)
  716.              else result
  717.              end if,
  718.        elem in sequence)
  719.   finally as(class-for-copy(sequence), reverse!(result));
  720.   end for;
  721. end choose;
  722.  
  723.  
  724. define method choose-by(predicate :: <function>, test-seq :: <sequence>,
  725.             value-seq :: <sequence>) => <sequence>;
  726.   for (result = #() then if (predicate(test-elem)) pair(value-elem, result)
  727.              else result
  728.              end if,
  729.        value-elem in value-seq, test-elem in test-seq)
  730.   finally as(class-for-copy(value-seq), reverse!(result));
  731.   end for;
  732. end method;
  733.  
  734.  
  735. define method intersection(sequence1 :: <sequence>, sequence2 :: <sequence>,
  736.                #key test = \==) => <sequence>;
  737.   choose(method (item) member?(item, sequence2, test: test) end method,
  738.      sequence1);
  739. end method intersection;
  740.  
  741.  
  742. define method difference(sequence1 :: <sequence>, sequence2 :: <sequence>,
  743.              #key test = \==) => <sequence>;
  744.   choose(method (item) ~member?(item, sequence2, test: test) end method,
  745.      sequence1);
  746. end method difference;
  747.  
  748.  
  749. define method union(sequence1 :: <sequence>, sequence2 :: <sequence>,
  750.             #key test = \==) => <sequence>;
  751.   concatenate(sequence1, difference(sequence2, sequence1,
  752.                     test: method(a, b) test(b,a) end method));
  753. end method union;
  754.  
  755.  
  756. define method remove-duplicates(sequence :: <sequence>,
  757.                 #key test = \==) => <sequence>;
  758.   local method true-test(a, b) test(b, a) end method;
  759.   for (result = #() then if (~member?(element, result, test: true-test))
  760.                pair(element, result);
  761.              else result
  762.              end if,
  763.        element in sequence)
  764.   finally as(class-for-copy(sequence), reverse!(result));
  765.   end for;
  766. end method remove-duplicates;
  767.  
  768.  
  769. define method remove-duplicates!(sequence :: <sequence>,
  770.                  #key test = \==) => <sequence>;
  771.   remove-duplicates(sequence, test: test);
  772. end method remove-duplicates!;
  773.  
  774.  
  775. define method copy-sequence(sequence :: <sequence>,
  776.                 #key start: first = 0, end: last) => <sequence>;
  777.   let last = if (last) min(last, size(sequence)) else size(sequence) end if;
  778.   let start = min(first, last);
  779.   let sz = if (start <= last) 
  780.          last - start;
  781.        else
  782.          error("End: (%=) is smaller than start: (%=)", last, start);
  783.        end if;
  784.   let result = make(class-for-copy(sequence), size: sz);
  785.   let (init-state, limit, next-state, done?,
  786.        current-key, current-element) = forward-iteration-protocol(sequence);
  787.  
  788.   for (index from 0 below start,
  789.        state = init-state then next-state(sequence, state))
  790.   finally
  791.     let (res-init, res-limit, res-next, res-done?, res-key,
  792.      res-elem, res-elem-setter) = forward-iteration-protocol(result);
  793.     for (index from index below last,
  794.      state = state then next-state(sequence, state),
  795.      res-state = res-init then res-next(result, res-state))
  796.       res-elem(result, res-state) := current-element(sequence, state);
  797.     end for;
  798.   end for;
  799.   result;
  800. end method copy-sequence;
  801.  
  802.  
  803. define method concatenate-as(cls :: <class>, sequence :: <sequence>,
  804.                  #rest more-sequences) => <sequence>;
  805.   if (size (sequence) == #f
  806.     | any? (method (s) size (s) == #f end, more-sequences))
  807.     error ("CONCATENATE-AS not applicable to unbounded sequences");
  808.   end if;
  809.   let length = reduce(method (int, seq) int + size(seq) end method,
  810.               size(sequence), more-sequences);
  811.   let result = make(cls, size: length);
  812.   let (init-state, limit, next-state, done?, current-key, current-element,
  813.        current-element-setter) = forward-iteration-protocol(result);
  814.   local method do-copy(state, seq :: <sequence>) // :: state
  815.       for (state = state then next-state(result, state),
  816.            elem in seq)
  817.         current-element(result, state) := elem;
  818.       finally state;
  819.       end for;
  820.     end method do-copy;
  821.   reduce(do-copy, do-copy(init-state, sequence), more-sequences);
  822.   result;
  823. end method concatenate-as;
  824.  
  825.  
  826. define method concatenate(sequence :: <sequence>,
  827.               #rest more-sequences) => <sequence>;
  828.   apply(concatenate-as, class-for-copy(sequence), sequence, more-sequences);
  829. end method concatenate;
  830.  
  831.  
  832. define method replace-subsequence!(sequence :: <mutable-sequence>,
  833.                    insert-sequence :: <sequence>,
  834.                    #key start: first = 0,
  835.                         end: last) => <sequence>;
  836.   let last = last | size(sequence);
  837.   concatenate(copy-sequence(sequence, start: 0, end: first), insert-sequence,
  838.           copy-sequence(sequence, start: last));
  839. end method replace-subsequence!;
  840.  
  841.  
  842. define method reverse(sequence :: <sequence>) => <sequence>;
  843.   let result = make(class-for-copy(sequence), size: size(sequence));
  844.   let (res-state, res-limit, res-next, res-done?, res-key, res-elem,
  845.        res-elem-setter) = forward-iteration-protocol(result);
  846.   let (source-state, source-limit, source-next, source-done?, source-key,
  847.        source-elem) = forward-iteration-protocol(sequence);
  848.   local method reverse1(res-state, source-state) // :: res-state
  849.       if (source-done?(sequence, source-state, source-limit))
  850.         res-state
  851.       else 
  852.         let elem = source-elem(sequence, source-state);
  853.         let new-res-state =
  854.           reverse1(res-state, source-next(sequence, source-state));
  855.         res-elem(result, new-res-state) := elem;
  856.         res-next(result, new-res-state);
  857.       end if;
  858.     end method reverse1;
  859.   reverse1(res-state, source-state);
  860.   result;
  861. end method;
  862.  
  863.  
  864. define method reverse!(sequence :: <sequence>) => <sequence>;
  865.   reverse(sequence);
  866. end method reverse!;
  867.  
  868.  
  869. define method first(sequence :: <sequence>, #rest keys, #key default)
  870.   apply(element, sequence, 0, keys);
  871. end method first;
  872.  
  873.  
  874. define method second(sequence :: <sequence>, #rest keys, #key default)
  875.   apply(element, sequence, 1, keys);
  876. end method second;
  877.  
  878.  
  879. define method third(sequence :: <sequence>, #rest keys, #key default)
  880.   apply(element, sequence, 2, keys);
  881. end method third;
  882.  
  883.  
  884. define method first-setter(value, sequence :: <sequence>)
  885.   sequence[0] := value;
  886. end method first-setter;
  887.  
  888.  
  889. define method second-setter(value, sequence :: <sequence>)
  890.   sequence[1] := value;
  891. end method second-setter;
  892.  
  893.  
  894. define method third-setter(value, sequence :: <sequence>)
  895.   sequence[2] := value;
  896. end method third-setter;
  897.  
  898.  
  899. define method last(sequence :: <sequence>, #rest keys, #key default)
  900.   apply(element, sequence, size(sequence) - 1, keys);
  901. end method last;
  902.  
  903.     
  904. define method last-setter(value, sequence :: <sequence>)
  905.   sequence[size(sequence) - 1] := value;
  906. end method last-setter;
  907.  
  908.     
  909. define method subsequence-position(big :: <sequence>, pattern :: <sequence>,
  910.                    #key test = \==, count = 1)
  911.  
  912.   let (init-state, limit, next-state, done?,
  913.        current-key, current-element,
  914.        current-element-setter, copy-state) = forward-iteration-protocol(big);
  915.   let (pat-init-state, pat-limit, pat-next-state,
  916.        pat-done?, pat-current-key, pat-current-element,
  917.        pat-current-element-setter,
  918.        pat-copy-state) = forward-iteration-protocol(pattern);
  919.   
  920.   if (empty?(pattern))
  921.     0
  922.   else
  923.     local method search(index, index-state, big-state, pat-state, count)
  924.         case
  925.           pat-done?(pattern, pat-state, pat-limit) =>
  926.         // End of pattern -- We found one.
  927.         if (count = 1)
  928.           index
  929.         else
  930.           let next = next-state(big, index-state);
  931.           search(index + 1, next, copy-state(big, next),
  932.              pat-copy-state(pattern, pat-init-state), count - 1);
  933.         end if;
  934.           done?(big, big-state, limit) =>
  935.         // End of big sequence -- it's not here.
  936.         #f;
  937.           test(current-element(big, big-state),
  938.            pat-current-element(pattern, pat-state)) =>
  939.         // They match -- try one more.
  940.         search(index, index-state, next-state(big, big-state),
  941.                pat-next-state(pattern, pat-state), count);
  942.           otherwise =>
  943.         // Don't match -- try one further along.
  944.         let next = next-state(big, index-state);
  945.             search(index + 1, next, next & copy-state(big, next),
  946.                pat-copy-state(pattern, pat-init-state), count);
  947.         end case;
  948.       end method search;
  949.     search(0, copy-state(big, init-state), copy-state(big, init-state),
  950.        pat-copy-state(pattern, pat-init-state), count);
  951.   end if;
  952. end method subsequence-position;
  953.  
  954.  
  955. // Stretchy collections -- se Design Note #27
  956. //
  957. define abstract class <stretchy-collection> (<collection>) end class;
  958.  
  959.  
  960. define method map-into(destination :: <stretchy-collection>,
  961.                proc :: <function>, coll :: <collection>,
  962.                #rest more-collections) => <stretchy-collection>;
  963.   let test1 = key-test(coll);
  964.   if (~instance?(destination, <mutable-collection>))
  965.     error("%= is not a mutable collection.", destination);
  966.   elseif (~ every?( method (c) test1 == key-test(c); end, more-collections ))
  967.     error("Can't map over collections with a different key tests");
  968.   elseif (~ (test1 == key-test(destination)))
  969.     error("Can't map into a collection with a different key test than its sources.");
  970.   elseif (empty?(more-collections))
  971.     for (key in key-sequence(destination))
  972.       destination[key] := proc(coll[key]);
  973.     end for;
  974.   else
  975.     let keys = reduce(rcurry(intersection, test: test1), key-sequence(coll),
  976.               map(key-sequence, more-collections));
  977.     for (key in keys)
  978.       destination[key] := apply(proc, coll[key],
  979.                 map(rcurry(element, key), more-collections));
  980.     end for;
  981.   end if;
  982.   destination;
  983. end method map-into;
  984.  
  985.  
  986. // We must define this method or the above method will be ambiguous with the
  987. // "<mutable-sequence>" method.
  988. //
  989. define method map-into(destination :: <stretchy-collection>,
  990.                proc :: <function>, sequence :: <sequence>,
  991.                #rest more-sequences)
  992.   let test1 = key-test(sequence);
  993.   if (~instance?(destination, <mutable-collection>))
  994.     error("%= is not a mutable collection.", destination);
  995.   elseif (~ every?( method (c) test1 == key-test(c); end, more-sequences ))
  996.     error("Can't map over collections with a different key tests");
  997.   elseif (~ (test1 == key-test(destination)))
  998.     error("Can't map into a collection with a different key test than its sources.");
  999.   elseif (empty?(more-sequences))
  1000.     let (res-init, res-limit, res-next, res-done?, res-key, res-elem,
  1001.      res-elem-setter) = forward-iteration-protocol(destination);
  1002.     let (src-init, src-limit, src-next, src-done?, src-key, src-elem)
  1003.       = forward-iteration-protocol(sequence);
  1004.     for (key from 0,
  1005.      src-state = src-init then src-next(sequence, src-state),
  1006.      res-state = res-init then res-next(destination, res-state),
  1007.      until src-done?(sequence, src-state, src-limit) |
  1008.        res-done?(destination, res-state, res-limit))
  1009.       res-elem(destination, res-state) := proc(src-elem(sequence, src-state));
  1010.     finally
  1011.       for (key from key,
  1012.        src-state = src-state then src-next(sequence, src-state),
  1013.        until src-done?(sequence, src-state, src-limit))
  1014.     destination[key] := proc(src-elem(sequence, src-state));
  1015.       end for;
  1016.     end for;
  1017.     destination;
  1018.   else
  1019.     // Duplicated code from "<collection>" method, to avoid next-method
  1020.     // ambiguity. 
  1021.     let keys = reduce(rcurry(intersection, test: test1), key-sequence(sequence),
  1022.               map(key-sequence, more-sequences));
  1023.     for (key in keys)
  1024.       destination[key] := apply(proc, sequence[key],
  1025.                 map(rcurry(element, key), more-sequences));
  1026.     end for;
  1027.     destination;
  1028.   end if;
  1029. end method map-into;
  1030.